package cn.b.sky.schedule.service.impl;

import cn.b.sky.common.constants.SystemConstant;
import cn.b.sky.common.exception.ImeException;
import cn.b.sky.common.exception.InfoException;
import cn.b.sky.common.model.Page;
import cn.b.sky.schedule.dao.TimedJobDao;
import cn.b.sky.schedule.job.TimeJobUtils;
import cn.b.sky.schedule.model.TimeJobInfoCondition;
import cn.b.sky.schedule.model.TimedJobInfo;
import cn.b.sky.schedule.service.TimedJobService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

@Service("timedJobService")
public class TimedJobServiceImpl implements TimedJobService {

  @Resource
  private TimedJobDao timedJobDao;

  @Resource
  private Scheduler scheduler;

  @Override
  public Page selectTimedJobList(TimeJobInfoCondition timedJobInfo) {
    try {
      if (null == timedJobInfo) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      //默认code排序
      if (StringUtils.isBlank(timedJobInfo.getOrderField())) {
        timedJobInfo.setOrderField("jobCode");
      }
      timedJobInfo.setData(timedJobDao.selectTimedJobList(timedJobInfo));
      timedJobInfo.setTotalCount(timedJobDao.selectTomeJobCount(timedJobInfo));
      return timedJobInfo;
    } catch (Exception e) {
      throw new InfoException(e);
    }
  }

  @Override
  public List<TimedJobInfo> selectEnableTimedJob(int enable) {
    return timedJobDao.selectEnableTimedJob(enable);
  }

  @Override
  public TimedJobInfo selectTimedJob(String jobCode) {
    try {
      if (null == jobCode) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      return timedJobDao.selectTimedJob(jobCode);
    } catch (Exception e) {
      throw new InfoException(e);
    }
  }

  @Override
  public void doEnableTimedJob(TimedJobInfo job) {
    try {
      if (null == job) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      // 修改定时作业状态启用
      job.setEnableFlag(SystemConstant.COMMON_STATUS_ON);
      timedJobDao.updateTimedJob(job);

      JobDetail jobDetail = scheduler.getJobDetail(new JobKey(job.getJobCode(), Scheduler.DEFAULT_GROUP));
      // 新建JobDetail
      if (null == jobDetail) {

        // 新建JobDetail
        jobDetail = TimeJobUtils.getJobDetail(job);
        // 新建定时器
        CronTriggerFactoryBean cornTrigger = TimeJobUtils.getTriggerBean(job);
        // 设置JobDetail，定时表达式
        cornTrigger.setJobDetail(jobDetail);
        // 加入调度器
        scheduler.addJob(jobDetail, true);
        scheduler.scheduleJob(cornTrigger.getObject());
      }
    } catch (Exception e) {
      throw new InfoException(e);
    }
  }

  @Override
  public void doDisableTimedJob(TimedJobInfo job) {
    try {
      if (null == job) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      // 修改定时作业状态 禁用
      job.setEnableFlag(SystemConstant.COMMON_STATUS_OFF);
      timedJobDao.updateTimedJob(job);
      JobKey key = new JobKey(job.getJobCode(), Scheduler.DEFAULT_GROUP);
      JobDetail jobDetail = scheduler.getJobDetail(key);
      // 新建JobDetail
      if (null != jobDetail) {
        scheduler.deleteJob(key);
      }
    } catch (Exception e) {
      throw new InfoException(e);
    }
  }

  @Override
  public void updateTimedConfig(TimedJobInfo job) {
    try {
      if (null == job) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      TimedJobInfo oldJob = selectTimedJob(job.getJobCode());
      // 持久化到数据库
      timedJobDao.updateTimedJob(job);
      //改变状态
      if (!oldJob.getEnableFlag().equals(job.getEnableFlag())) {
        JobKey key = new JobKey(job.getJobCode(), Scheduler.DEFAULT_GROUP);
        //禁用则删除定时任务
        if (job.getEnableFlag() == SystemConstant.COMMON_STATUS_OFF) {
          JobDetail jobDetail = scheduler.getJobDetail(key);
          // 新建JobDetail
          if (null != jobDetail) {
            scheduler.deleteJob(key);
          }
        } else if (job.getEnableFlag() == SystemConstant.COMMON_STATUS_ON) {
          addJobToScheduler(job);
        }
      }
      //改变表达式
      if (!oldJob.getCronExpression().equals(job.getCronExpression())) {
        //重新载入job
        rescheduleJob(job);
      }
    } catch (SchedulerException e) {
      throw ImeException.newException(e, "job_notExists.M", new String[] { job.getJobCode() });
    } catch (ClassNotFoundException e) {
      throw ImeException.newException(e, "jobClass_notExists.M", new String[] { job.getJobClass() });
    } catch (ParseException e) {
      throw ImeException.newException(e, "job_cronExpressionError.M", new String[] { job.getCronDesc() });
    } catch (NoSuchMethodException e) {
      throw ImeException.newException(e, "jobMethod_notExists.M", new String[] { "executeManual" });
    }
  }

  private void rescheduleJob(TimedJobInfo job) throws SchedulerException, ParseException {
    CronTriggerFactoryBean cronTrigger = TimeJobUtils.getTriggerBean(job);
    // 新建JobDetail
    if (null != cronTrigger) {
      // 设置定时表达式
      cronTrigger.setCronExpression(job.getCronExpression());
      if (!StringUtils.isBlank(job.getJavaTimeZone())) {
        cronTrigger.setTimeZone(TimeZone.getTimeZone(job.getJavaTimeZone()));
      }
      // 重新加入调度器
      scheduler.rescheduleJob(new TriggerKey(job.getJobCode(), Scheduler.DEFAULT_GROUP), cronTrigger.getObject());
    }
  }

  @Override
  public void doExecuteTimedJob(TimedJobInfo job) throws Exception {
    try {
      if (null == job) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      
      JobDetail jobDetail = TimeJobUtils.getJobDetail(job);
      if(null ==  this.scheduler.getJobDetail(jobDetail.getKey())){
        //如果不为空则加入scheduler中，以异步方式执行作业
        // 加入调度器
        scheduler.addJob(jobDetail, true);
      }
      this.scheduler.triggerJob(jobDetail.getKey());
    } catch (ClassNotFoundException e) {
      throw ImeException.newException(e, "job_notExists.M", new String[] { job.getJobClass() });
    }
  }

  @Override
  public void updateLastExecTime(String jobCode) {
    try {
      if (null == jobCode) {
        throw ImeException.newException(SystemConstant.PARAMETERNULL);
      }
      TimedJobInfo job = timedJobDao.selectTimedJob(jobCode);
      if (null != job) {
        job.setLastExecutionTime(new Date());
        timedJobDao.updateTimedJob(job);
      }
    } catch (Exception e) {
      throw new InfoException(e);
    }
  }

  @Override
  public void saveTimedConfig(TimedJobInfo job) {
    if (job == null || StringUtils.isBlank(job.getJobCode())) {
      return;
    }
    timedJobDao.insertTimedConfig(job);
    if (job.getEnableFlag() == SystemConstant.COMMON_STATUS_ON) {
      try {
        addJobToScheduler(job);
      } catch (SchedulerException e) {
        throw ImeException.newException(e, "job_notExists.M", new String[] { job.getJobCode() });
      } catch (ClassNotFoundException e) {
        throw ImeException.newException(e, "jobClass_notExists.M", new String[] { job.getJobClass() });
      } catch (ParseException e) {
        throw ImeException.newException(e, "job_cronExpressionError.M", new String[] { job.getCronDesc() });
      } catch (NoSuchMethodException e) {
        throw ImeException.newException(e, "jobMethod_notExists.M", new String[] { "executeManual" });
      }
    }
  }

  private void addJobToScheduler(TimedJobInfo job)
      throws SchedulerException, ClassNotFoundException, ParseException, NoSuchMethodException {

    JobDetail jobDetail = scheduler.getJobDetail(new JobKey(job.getJobCode(), Scheduler.DEFAULT_GROUP));
    if(null == jobDetail){
      // 新建JobDetail
      jobDetail = TimeJobUtils.getJobDetail(job);
      // 加入调度器
      scheduler.addJob(jobDetail, true);
    }

    CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(new TriggerKey(job.getJobCode(), Scheduler.DEFAULT_GROUP));
    // 新建JobDetail
    if (null == cronTrigger) {
      // 新建定时器
      CronTriggerFactoryBean cronTriggerFactoryBean = TimeJobUtils.getTriggerBean(job);
      // 设置JobDetail，定时表达式
      cronTriggerFactoryBean.setJobDetail(jobDetail);
      scheduler.scheduleJob(cronTriggerFactoryBean.getObject());
    } else {
      rescheduleJob(job);
    }
  }

  @Override
  public void deleteTimedJob(String jobCode) {
    if (null == jobCode) {
      throw ImeException.newException(SystemConstant.PARAMETERNULL);
    }
    timedJobDao.deleteTimedJob(jobCode);
    JobDetail jobDetail;
    try {
      jobDetail = scheduler.getJobDetail(new JobKey(jobCode, Scheduler.DEFAULT_GROUP));
      if (null != jobDetail) {
        scheduler.deleteJob(jobDetail.getKey());
      }
    } catch (SchedulerException e) {
      throw new InfoException(e);
    }
  }

  @Override
  public boolean checkTimedJob(String jobCode) {
    return timedJobDao.checkTimedJob(jobCode) >= 1;
  }
}
